package net.sea.setup.boot;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.UIManager;

import cn.hutool.core.io.resource.ResourceUtil;
import com.gitee.swsk33.reg.RegQuery;
import com.gitee.swsk33.reg.param.RegPrimaryKey;
import org.pushingpixels.substance.api.skin.SubstanceCeruleanLookAndFeel;


import net.sea.commons.constants.AppConstants;
import net.sea.commons.context.AppContext;
import net.sea.commons.util.JAXBUtils;
import net.sea.commons.util.OsUtils;
import net.sea.commons.util.StringUtils;
import net.sea.setup.action.Setup;
import net.sea.setup.config.Page;
import net.sea.setup.config.Wizard;
import net.sea.setup.config.custom.CustomConfig;
import net.sea.setup.ui.menu.MenuPanel;
import net.sea.setup.ui.wizard.AbstractWizardPage;
import net.sea.setup.ui.wizard.WizardPanel;
import org.apache.log4j.Logger;

/**
 * 易开平台安装向导主程序
 *
 * @author 华成伍
 */
public class BootStrap {
    private static Logger logger = Logger.getLogger(BootStrap.class);
    // 弹出消息框状态
    private final static int OK = 1;// 确定
    private final static int CANCEL = 0;// 取消
    private final static int OTHER = -1;// 其他
    private final static String RUN_MODEL = "silent";
    private final static String SILENT_FILENAME = "silent_install.properties";

    // 向导配置信息对象
    private static Wizard wizard = new Wizard();

    private JFrame mainFrame;
    private JButton preBtn = new JButton("\u4E0A\u4E00\u6B65");
    private JButton nextBtn = new JButton("\u4E0B\u4E00\u6B65");
    private JButton cancelBtn = new JButton("\u53D6\u6D88");
    private JButton finishBtn = new JButton("\u5B8C\u6210");
    private final MenuPanel menuPanel = new MenuPanel();
    private final WizardPanel wizardPanel = new WizardPanel();
    // 获取上下文实例对象
    private static AppContext contextInst = AppContext.getInstance();
    // 根容器
    private final JPanel rootPanel = new JPanel() {
        private static final long serialVersionUID = 7662474433127063499L;

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            int x = 0, y = 0;
            java.net.URL imgURL = BootStrap.class.getResource("/img/bg.jpg");
            // test.jpg是测试图片，与Demo.java放在同一目录下
            ImageIcon icon = createAlphaIcon(new ImageIcon(imgURL), 0.1f);
            g.drawImage(icon.getImage(), x, y, getSize().width,
                    getSize().height, this);
            while (true) {
                g.drawImage(icon.getImage(), x, y, this);
                if (x > getSize().width && y > getSize().height)
                    break;
                // 这段代码是为了保证在窗口大于图片时，图片仍能覆盖整个窗口
                if (x > getSize().width) {
                    x = 0;
                    y += icon.getIconHeight();
                } else {
                    x += icon.getIconWidth();
                }
            }
        }
    };

    public static ImageIcon createAlphaIcon(ImageIcon icon, float alpha) {
        int w = icon.getIconWidth();
        int h = icon.getIconHeight();
        BufferedImage bimage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = bimage.createGraphics();
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
        icon.paintIcon(null, g2, 0, 0);
        g2.dispose();
        return new ImageIcon(bimage);
    }

    // 加载系统配置信息
    static {
        // 初始化用户自定义配置Map
        contextInst.setAttribute(AppConstants.CUSTOM_CONFIG_KEY,
                new LinkedHashMap<String, CustomConfig>());
        contextInst.setAttribute(AppConstants.CUSTOM_CONFIG_MAP_KEY,
                new HashMap<String, CustomConfig>());
        // 安装目录
        contextInst.setAttribute(AppConstants.INSTALL_ROOT_KEY,
                AppConstants.SYSTEM_PATH);
        if (logger.isDebugEnabled()) {
            logger.debug("是否为windows操作系统：" + OsUtils.isFamily("windows"));
        }
        if (OsUtils.isFamily("windows")) {
            // 开始菜单路径
//			RegistryKey reg = new RegistryKey(RootKey.HKEY_CURRENT_USER,
//					"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders");
//            String menuFolder = reg.getValue("Programs").getStringValue()
//                    + "/自动化测试平台";
            String reg = null;
            try {
                reg = RegQuery.queryValue(RegPrimaryKey.HKCU,
                        "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
                        "Programs");
            } catch (Exception e) {
                logger.error("获取注册表信息失败", e);
                throw new RuntimeException(e);
            }
            String menuFolder = reg + "/自动化测试平台";
            // 创建开始菜单目录
            menuFolder = createMenuFolder(menuFolder);
            contextInst.setAttribute(AppConstants.CURRENT_USER_START_MENU_KEY,
                    menuFolder);
            if (logger.isDebugEnabled()) {
                logger.debug("开始菜单路径：" + menuFolder);
            }
        }
        load();
    }

    /**
     * 计算开始菜单目录
     *
     * @param menuFolder 原始的开始菜单目录
     * @return 创建后的开始菜单目录
     */
    private static String createMenuFolder(String menuFolder) {
        logger.info("计算开始菜单目录");
        File menuFile = new File(menuFolder);
        if (menuFile.exists()) {
            // 检查开始菜单目录是否存在，如果存在递次加1
            for (int i = 1; true; i++) {
                menuFile = new File(menuFolder + i);
                if (!menuFile.exists()) {
                    break;
                }
            }
        }
        return menuFile.getAbsolutePath();
    }

    /**
     * 加载应用程序
     */
    public static void main(String[] args) {
        // System.setProperty("Quaqua.tabLayoutPolicy", "wrap");
        String run_model = System.getProperty("install.runmode");
        if (RUN_MODEL.equals(run_model)) {
            // 解析雅安装配置文件
            String silent_file = AppConstants.SYSTEM_PATH + File.separator
                    + "install" + File.separator + SILENT_FILENAME;
            Properties pop = new Properties();
            try {
                pop.load(new FileInputStream(new File(silent_file)));
            } catch (FileNotFoundException e) {
                logger.error("未找到哑安装配置文件", e);
            } catch (IOException e) {
                logger.error("哑安装配置文件加载异常", e);
            }
            // 初始化安装包上下文对象
            initContext(pop);

            // 执行安装
            Setup setup = new Setup(contextInst);
            setup.start(Setup.INSTALL);
        } else {
            try {
                UIManager.setLookAndFeel(new SubstanceCeruleanLookAndFeel());
                if (logger.isDebugEnabled()) {
                    logger.debug("安装程序启动");
                }
            } catch (Exception e) {
                logger.error("安装界面皮肤设置异常", e);
                System.exit(0);
            }

            try {
                EventQueue.invokeLater(new Runnable() {
                    public void run() {
                        BootStrap window = new BootStrap();
                        window.mainFrame.setVisible(true);
                    }
                });
            } catch (Exception e) {
                logger.error("安装程序异常", e);
                System.exit(0);
            }
        }
    }

    /**
     * 初始化安装包上下文对象
     *
     * @param pop
     */
    private static void initContext(Properties pop) {
        contextInst
                .setAttribute(AppConstants.DB_URL, pop.getProperty("DB_URL"));
        contextInst.setAttribute(AppConstants.DB_USER,
                pop.getProperty("DB_USER"));
        contextInst.setAttribute(AppConstants.DB_PWD,
                pop.getProperty("DB_PASSWORD"));
        contextInst.setAttribute(AppConstants.DB_DRIVER_CLASS,
                pop.getProperty("DB_DRIVER_CLASS"));
        contextInst.setAttribute(AppConstants.DB_DRIVER_JAR,
                pop.getProperty("DB_DRIVER_JAR"));
        String dbInitFlag = pop.getProperty("DB_INIT_FLAG");
        contextInst
                .setAttribute(
                        AppConstants.DB_INIT_FLAG,
                        StringUtils.isEmpty(dbInitFlag) ? false : Boolean
                                .parseBoolean(dbInitFlag));
        contextInst.setAttribute(AppConstants.DB_TYPE,
                pop.getProperty("DB_TYPE"));
        contextInst.setAttribute(AppConstants.INSTALL_DIR_KEY,
                pop.getProperty("INSTALL_DIR_KEY"));

    }

    /**
     * 创建应用程序窗口
     *
     * @wbp.parser.entryPoint
     */
    public BootStrap() {
        // init();
        initialize();
    }

    /**
     * 加载系统配置
     */
    private static void load() {
        // jar包中配置文件的读取使用classloader的getResourceAsStream()方法，jar外的资源使用System.getProperty("user.dir")确定位置
//		wizard = (Wizard) (JAXBUtils.xmlToBean(BootStrap.class.getClassLoader()
//						.getResourceAsStream("com/ec/setup/config/config.xml"),
//				Wizard.class));
        wizard = (Wizard) (JAXBUtils.xmlToBean(ResourceUtil.getStream("config/config.xml"),
                Wizard.class));

        if (wizard == null) {
            throw new RuntimeException("系统配置错误，请检查。");
        }
        List<Page> pages = wizard.getPages();
        if (pages == null) {
            throw new RuntimeException("系统配置信息有误");
        }
        Map<String, String> dataMap = new HashMap<String, String>();
        // 读取页面
        for (Page page : pages) {
            String dataFile = page.getDataFile();
            if (StringUtils.isNotEmpty(dataFile)) {
                // dataMap.put(page.getPanelClass(), FileUtils
                // .read(BootStrap.class.getClassLoader()
                // .getResourceAsStream(dataFile)));
                dataMap.put(page.getPanelClass(), dataFile);
            } else {
                dataMap.put(page.getPanelClass(), null);
            }
        }
        contextInst.setAttribute(AppConstants.DATA_FILE, dataMap);

        // 根据页面index对页面对象进行排序
        Collections.sort(pages, new Comparator<Page>() {
            @Override
            public int compare(Page page1, Page page2) {
                if (page1 == null || page2 == null) {
                    return 1;
                }
                if (page1.getIndex() > page2.getIndex()) {
                    return 1;
                } else if (page1.getIndex() == page2.getIndex()) {
                    return 0;
                } else {
                    return -1;
                }
            }
        });
        boolean[] neededButtons = null;
        if (pages == null || pages.isEmpty()) {
            neededButtons = new boolean[]{false, false, false, false};
        } else if (pages.size() == 1) {
            neededButtons = new boolean[]{false, false, true, false};
        } else {
            neededButtons = new boolean[]{false, true, false, true};
        }
        contextInst.setAttribute(AppConstants.CFG_WIZARD_KEY, wizard);
        contextInst.setAttribute(AppConstants.NEEDEDS_BUTTONS_KEY,
                neededButtons);
    }

    /**
     * 初始化页面布局
     */
    private void initialize() {
        mainFrame = new JFrame();
        mainFrame.setResizable(false);
        mainFrame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                exit();
            }
        });
        mainFrame.setIconImage(Toolkit.getDefaultToolkit().getImage(
                AppConstants.SYSTEM_PATH + wizard.getSysLogo()));
        mainFrame.setTitle(wizard.getSysTitle());
        int width = 1024;
        int height = 768;
        Dimension screen = mainFrame.getToolkit().getScreenSize();
        int posX = (screen.width - width) / 2;
        int posY = (screen.height - height) / 2;
        mainFrame.setBounds(posX, posY, width, height);
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.getContentPane().setLayout(new BorderLayout(0, 0));

        mainFrame.getContentPane().add(rootPanel, BorderLayout.CENTER);
        rootPanel.setLayout(new BorderLayout(0, 0));

        JSplitPane contentPanel = new JSplitPane();
        rootPanel.add(contentPanel, BorderLayout.CENTER);
        contentPanel.setEnabled(false);
        // 设置分割比例
        contentPanel.setResizeWeight(0.1);
        // 设置分割线的大小
        contentPanel.setDividerSize(0);
        menuPanel.setOpaque(false);
        contentPanel.setLeftComponent(menuPanel);
        wizardPanel.setOpaque(false);
        contentPanel.setRightComponent(wizardPanel);
        contentPanel.setOpaque(false);

        JPanel bottomPanel = new JPanel();
        bottomPanel.setOpaque(false);
        rootPanel.add(bottomPanel, BorderLayout.SOUTH);
        FlowLayout fl_bottomPanel = (FlowLayout) bottomPanel.getLayout();
        fl_bottomPanel.setAlignment(FlowLayout.RIGHT);
        preBtn.addActionListener(e -> {
            int pageType = wizardPanel.previous();
            setBottons(pageType);
        });
        bottomPanel.add(preBtn);
        nextBtn.addActionListener(e -> {
            int pageType = wizardPanel.next();
            setBottons(pageType);
        });
        bottomPanel.add(nextBtn);
        finishBtn.addActionListener(e -> {
            //
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                List<AbstractWizardPage> pagePanels = (List<AbstractWizardPage>) contextInst
                        .getAttribute(AppConstants.WIZARD_PAGES_KEY);
                if (pagePanels != null) {
                    AbstractWizardPage page = pagePanels.get(pagePanels
                            .size() - 1);
                    page.done();
                }
            }));
            mainFrame.dispose();
        });
        bottomPanel.add(finishBtn);
        cancelBtn.addActionListener(e -> {
            boolean flag = contextInst
                    .getAttribute(AppConstants.ROLLBACK_FLAG) == null ? false
                    : (Boolean) contextInst
                    .getAttribute(AppConstants.ROLLBACK_FLAG);
            if (exit() == OK) {
                if (flag) {
                    logger.info("rollback……");
                    rollback();
                }
                System.exit(0);
            }
        });
        bottomPanel.add(cancelBtn);

        wizardPanel.addButton(preBtn);

        wizardPanel.addButton(nextBtn);

        wizardPanel.addButton(finishBtn);

        wizardPanel.addButton(cancelBtn);
        boolean[] neededBtns = (boolean[]) contextInst
                .getAttribute(AppConstants.NEEDEDS_BUTTONS_KEY);
        setBottons(neededBtns[0], neededBtns[1], neededBtns[2], neededBtns[3]);
    }

    /**
     * 安装回滚
     */
    private void rollback() {
        // TODO 未实现
        // // 停止安装程序
        // Thread thread = (Thread) contextInst
        // .getAttribute(AppConstants.SETUP_THREAD_KEY);
        // if (thread != null) {
        // thread.interrupt();
        // }
        // // 删除安装目录
        // String installDir = (String) contextInst
        // .getAttribute(AppConstants.INSTALL_DIR_KEY);
        // FileUtils.delete(new File(installDir));
        // // 删除开始菜单
        // String menuDir = (String) contextInst
        // .getAttribute(AppConstants.CURRENT_USER_START_MENU_KEY);
        // FileUtils.delete(new File(menuDir));
    }

    /**
     * 根据页面状态设置按钮状态
     *
     * @param pageType 页面类型
     */
    @SuppressWarnings("unchecked")
    private void setBottons(int pageType) {
        boolean[] neededBtns = (boolean[]) contextInst
                .getAttribute(AppConstants.NEEDEDS_BUTTONS_KEY);
        if (pageType == WizardPanel.FIRST_PAGE) {
            List<AbstractWizardPage> pagePanels = (List<AbstractWizardPage>) contextInst
                    .getAttribute(AppConstants.WIZARD_PAGES_KEY);
            if (pagePanels == null || pagePanels.isEmpty()) {
                setBottons(false, false, false, false);
            } else if (pagePanels.size() == 1) {
                setBottons(false, false, true, false);
            } else {
                setBottons(false, true, false, true);
            }
        } else if (pageType == WizardPanel.MIDDLE_PAGE) {
            if (neededBtns != null) {
                setBottons(neededBtns[0], neededBtns[1], neededBtns[2],
                        neededBtns[3]);
            } else {
                setBottons(true, true, false, true);
            }
        } else if (pageType == WizardPanel.LAST_PAGE) {
            setBottons(false, false, true, false);
        }
    }

    /**
     * 初始化菜单以及向导页
     */
    // private void init() {
    // menuPanel = new MenuPanel();
    // IntroductionPage inPage = new IntroductionPage();
    // inPage.setIndex(102);
    // wizardPanel.addWizardPage(inPage);
    // LicensePage licensePage = new LicensePage(mainFrame);
    // licensePage.setIndex(100);
    // wizardPanel.addWizardPage(licensePage);
    // DBPage dbPage1 = new DBPage();
    // dbPage1.setIndex(1212);
    // wizardPanel.addWizardPage(dbPage1);
    // }

    /**
     * 设置按钮显示状态
     *
     * @param preBtn    上一步按钮状态
     * @param nextBtn   下一步按钮状态
     * @param finishBtn 完成按钮显示状态
     * @param cancelBtn 取消按钮状态
     */
    public void setBottons(boolean preBtn, boolean nextBtn, boolean finishBtn,
                           boolean cancelBtn) {
        this.preBtn.setVisible(preBtn);
        this.nextBtn.setVisible(nextBtn);
        this.finishBtn.setVisible(finishBtn);
        this.cancelBtn.setVisible(cancelBtn);
    }

    /**
     * 退出
     */
    private int exit() {
        Object[] options = {"确定", "取消"};
        JOptionPane opPanel = new JOptionPane("是否要退出安装程序?",
                JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION, null,
                options, options[1]);
        JDialog dialog = opPanel.createDialog(mainFrame, "提示信息");
        dialog.setVisible(true);
        Object selectedValue = opPanel.getValue();
        if (selectedValue == null || selectedValue == options[1]) {
            mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
            return CANCEL;
        } else if (selectedValue == options[0]) {
            mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            return OK;
        }
        return OTHER;
    }
}
